Don't infinitely recurse on cyclic path deps
authorAlex Crichton <alex@alexcrichton.com>
Sat, 28 Jun 2014 20:33:29 +0000 (13:33 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Mon, 30 Jun 2014 20:18:14 +0000 (13:18 -0700)
Instead, keep a table of what we've visited and halt recursion whenever we
re-visit a package.

Closes #77

src/cargo/ops/cargo_read_manifest.rs
tests/test_cargo_compile.rs

index 262e502af9e6d60fcfa54d8b7ad3f387a60df725..91dbc63615981d20498227cb0fbfe1e9e81e9069 100644 (file)
@@ -1,3 +1,4 @@
+use std::collections::HashSet;
 use std::io::File;
 use util;
 use core::{Package,Manifest,SourceId};
@@ -24,13 +25,23 @@ pub fn read_package(path: &Path, source_id: &SourceId)
 pub fn read_packages(path: &Path, source_id: &SourceId)
     -> CargoResult<Vec<Package>>
 {
-    let manifest = try!(important_paths::find_project_manifest_exact(path, "Cargo.toml"));
-    let (pkg, nested) = try!(read_package(&manifest, source_id));
-    let mut ret = vec!(pkg);
+    return read_packages(path, source_id, &mut HashSet::new());
 
-    for p in nested.iter() {
-        ret.push_all(try!(read_packages(&path.join(p), source_id)).as_slice());
-    }
+    fn read_packages(path: &Path, source_id: &SourceId,
+                     visited: &mut HashSet<Path>) -> CargoResult<Vec<Package>> {
+        if !visited.insert(path.clone()) { return Ok(Vec::new()) }
+
+        let manifest = try!(important_paths::find_project_manifest_exact(path,
+                                                                         "Cargo.toml"));
+        let (pkg, nested) = try!(read_package(&manifest, source_id));
+        let mut ret = vec![pkg];
 
-    Ok(ret)
+        for p in nested.iter() {
+            ret.push_all(try!(read_packages(&path.join(p),
+                                            source_id,
+                                            visited)).as_slice());
+        }
+
+        Ok(ret)
+    }
 }
index f7497360ae538e62ca4a3361df61d9fdd6c135a2..9fa6a8aa8b1b0e4e29014fc8a4ebb232d2fc7067 100644 (file)
@@ -603,3 +603,26 @@ test!(unused_keys {
                 execs().with_status(0)
                        .with_stderr("unused manifest key: lib.build\n"));
 })
+
+test!(self_dependency {
+    let mut p = project("foo");
+    p = p
+        .file("Cargo.toml", r#"
+            [package]
+
+            name = "test"
+            version = "0.0.0"
+            authors = []
+
+            [dependencies.test]
+
+            path = "."
+
+            [[lib]]
+
+            name = "test"
+        "#)
+        .file("src/test.rs", "fn main() {}");
+    assert_that(p.cargo_process("cargo-build"),
+                execs().with_status(0));
+})